package com.lzhl.buildjar.ui;

import com.lzhl.buildjar.App;
import com.lzhl.buildjar.dao.CategoryDao;
import com.lzhl.buildjar.dao.DaoFactory;
import com.lzhl.buildjar.dao.SchemeDao;
import com.lzhl.buildjar.po.Category;
import com.lzhl.buildjar.po.Scheme;
import com.lzhl.buildjar.ui.support.Cmd;
import com.lzhl.buildjar.ui.support.CmdListener;
import com.lzhl.buildjar.ui.support.OperationListener;
import com.lzhl.buildjar.util.ImageUtils;
import com.lzhl.buildjar.util.UIUtils;

import javax.swing.*;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.Enumeration;

/**
 * @author 李柱良(@柱子的日月)
 * @date 2014/6/19
 */
public class CategoryTreeUI extends JTree implements
        TreeExpansionListener, TreeSelectionListener, ActionListener, CmdListener {

    private CategoryDao categoryDao = (CategoryDao) DaoFactory.getDao("categoryDao");
    private SchemeDao schemeDao = (SchemeDao) DaoFactory.getDao("schemeDao");

    private DefaultTreeModel treeModel;

    private JPopupMenu popMenu;
    private JMenuItem miAddCategory;
    private JMenuItem miAddScheme;
    private JMenuItem miEditItem;
    private JMenuItem miCopyItem;
    private JMenuItem miDelItem;

    private Scheme scheme = null;

    public CategoryTreeUI() {
        jbinit();
        init();
    }

    private void jbinit() {
        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        setRowHeight(20);

        popMenu = new JPopupMenu();

        miAddCategory = new JMenuItem("新增分类");
        miAddScheme = new JMenuItem("新增方案");
        miEditItem = new JMenuItem("修改");
        miCopyItem = new JMenuItem("复制");
        miDelItem = new JMenuItem("删除");

        popMenu.add(miAddCategory);
        popMenu.add(miAddScheme);
        popMenu.add(miEditItem);
        popMenu.add(miCopyItem);
        popMenu.add(miDelItem);

        miAddCategory.addActionListener(this);
        miAddScheme.addActionListener(this);
        miEditItem.addActionListener(this);
        miCopyItem.addActionListener(this);
        miDelItem.addActionListener(this);
    }

    private void init() {
        CategoryTreeNode rootNode = new CategoryTreeNode(Category.ROOT);
        rootNode.load();

        treeModel = new DefaultTreeModel(rootNode);
        setModel(treeModel);

        getSelectionModel().setSelectionMode(
                TreeSelectionModel.SINGLE_TREE_SELECTION);

        setCellRenderer(new CategoryTreeCellRenderer());

        addTreeExpansionListener(this);
        addTreeSelectionListener(this);
        addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                tree_mouseClicked(e);
            }
        });

        InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED);
        ActionMap actionMap = getActionMap();
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "shortcutkey_delete");
        actionMap.put("shortcutkey_delete", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                delItem_actionPerformed(e);
            }
        });
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), "shortcutkey_edit");
        actionMap.put("shortcutkey_edit", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                editItem_actionPerformed(e);
            }
        });
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "shortcutkey_scheme_focus");
        actionMap.put("shortcutkey_scheme_focus", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                App.fireCmd(Cmd.SCHEME_FOCUS);
            }
        });

        App.registCmdListener(this);
        setSelectionRow(0);
    }

    //方向键
//    public void setSelectionInterval(int index0, int index1) {
//        checkSave();
//        super.setSelectionInterval(index0, index1);
//    }

    //鼠标点击
//    public void setSelectionPath(TreePath path) {
//        checkSave();
//        super.setSelectionPath(path);
//    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == miAddCategory) {
            addCategory_actionPerformed(e);
        }
        else if(e.getSource() == miAddScheme) {
            addScheme_actionPerformed(e);
        }
        else if (e.getSource() == miEditItem) {
            editItem_actionPerformed(e);
        }
        else if (e.getSource() == miCopyItem) {
            copyItem_actionPerformed(e);
        }
        else if (e.getSource() == miDelItem) {
            delItem_actionPerformed(e);
        }
    }

    @Override
    public Object handleCmd(Cmd cmd, Object data) {
        if(cmd.equals(Cmd.CATEGORY_ADD)) {
            addCategory_actionPerformed(null);
        }
        else if(cmd.equals(Cmd.SCHEME_ADD)) {
            addScheme_actionPerformed(null);
        }
        else if(cmd.equals(Cmd.SCHEME_DEL)) {
            delItem_actionPerformed(null);
        }
        else if(cmd.equals(Cmd.CATEGORY_FOCUS)) {
            if(!this.hasFocus()) {
                this.requestFocus();
            }
        }

        return null;
    }

    @Override
    public void treeExpanded(TreeExpansionEvent event) {
        TreePath path=event.getPath();
        CategoryTreeNode node = (CategoryTreeNode)path.getLastPathComponent();
        this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
//        this.setEnabled(false);

        node.load();

//        this.setEnabled(true);
        this.setCursor(Cursor.getDefaultCursor());
    }

    @Override
    public void treeCollapsed(TreeExpansionEvent event) {

    }

    @Override
    public void valueChanged(TreeSelectionEvent e) {
        checkSave();

        CategoryTreeNode node = (CategoryTreeNode) getLastSelectedPathComponent();
        if(node == null) {
            return;
        }

        Object object = node.getUserObject();
        if(object instanceof Scheme) {
            scheme = (Scheme) object;
            //不改变图标，不需要重绘
//            repaint();
        }
        else {
            scheme = null;
        }
        App.fireCmd(Cmd.SCHEME_OPEN, scheme);
    }

    public void tree_mouseClicked(MouseEvent e) {
        TreePath path = getPathForLocation(e.getX(), e.getY());
        if (path == null) {
            return;
        }
        setSelectionPath(path);

        CategoryTreeNode node = (CategoryTreeNode) getLastSelectedPathComponent();
        Object object = node.getUserObject();

        if (e.getButton() == 3) {
            if(object == Category.ROOT) {
                miEditItem.setVisible(false);
                miDelItem.setVisible(false);
            }
            else {
                miEditItem.setVisible(true);
                miDelItem.setVisible(true);
            }
            miAddCategory.setVisible(object instanceof Category);
            miAddScheme.setVisible(object instanceof Category);
            miCopyItem.setVisible(object instanceof Scheme);
            popMenu.show(this, e.getX()+5, e.getY()+5);
        }
    }

    private void addCategory_actionPerformed(ActionEvent e) {
        final CategoryTreeNode node = (CategoryTreeNode) getLastSelectedPathComponent();
        Object object = node.getUserObject();
        if(!(object instanceof  Category)) {
            return;
        }
        Category parent = (Category) object;
        new CategoryEditUI((Frame)getTopLevelAncestor(), parent, null, new OperationListener() {
            @Override
            public void operationPerformed(Object object) {
                Category c = (Category) object;
                node.load();
                categoryDao.addCategory(c);
                expandPath(getSelectionPath());

                int index = node.getChildCount();
                for(int i = 0; i < node.getChildCount(); i++) {
                    CategoryTreeNode child = (CategoryTreeNode) node.getChildAt(i);
                    if(child.getUserObject() instanceof Scheme) {
                        index = i;
                        break;
                    }
                }

                CategoryTreeNode nNode = new CategoryTreeNode(c);
                ((DefaultTreeModel) getModel()).insertNodeInto(nNode, node, index);
                setSelectionPath(new TreePath(nNode.getPath()));
            }
        });
    }

    private void addScheme_actionPerformed(ActionEvent e) {
        final CategoryTreeNode node = (CategoryTreeNode) getLastSelectedPathComponent();
        Object object = node.getUserObject();
        if(object instanceof Category) {
            Category category = (Category) object;
            new SchemeEditUI((Frame)getTopLevelAncestor(), category, null, new OperationListener() {
                @Override
                public void operationPerformed(Object object) {
                    Scheme s = (Scheme) object;
                    node.load();
                    schemeDao.addScheme(s);
                    expandPath(getSelectionPath());

                    CategoryTreeNode nNode = new CategoryTreeNode(s);
                    ((DefaultTreeModel) getModel()).insertNodeInto(nNode, node, node.getChildCount());
                    scheme = null;
                    setSelectionPath(new TreePath(nNode.getPath()));
                }
            });
        }
        else {
            copyItem_actionPerformed(e);
        }
    }

    private void editItem_actionPerformed(ActionEvent e) {
        final CategoryTreeNode node = (CategoryTreeNode) getLastSelectedPathComponent();
        if (node.isRoot()) {
            return;
        }

        CategoryTreeNode parentNode = (CategoryTreeNode) node.getParent();
        Category parent = (Category) parentNode.getUserObject();
        Object me = node.getUserObject();
        if(me instanceof Category) {
            new CategoryEditUI((Frame)getTopLevelAncestor(), parent, (Category)me, new OperationListener() {
                @Override
                public void operationPerformed(Object object) {
                    categoryDao.saveCategory((Category)object);
                    treeModel.nodeChanged(node);
                }
            });
        }
        else if(me instanceof Scheme) {
            new SchemeEditUI((Frame)getTopLevelAncestor(), parent, (Scheme)me, new OperationListener() {
                @Override
                public void operationPerformed(Object object) {
                    App.fireCmd(Cmd.SCHEME_SEND, object);
                    treeModel.nodeChanged(node);
                }
            });
        }
    }

    private void copyItem_actionPerformed(ActionEvent e) {
        checkSave();

        CategoryTreeNode node = (CategoryTreeNode) getLastSelectedPathComponent();
        final  CategoryTreeNode parentNode = (CategoryTreeNode) node.getParent();
        Category parent = (Category) parentNode.getUserObject();
        final Scheme me = (Scheme) node.getUserObject();
        Scheme s = new Scheme();
        s.setName(me.getName());
        s.setCategory(me.getCategory());

        new SchemeEditUI((Frame)getTopLevelAncestor(), parent, s, new OperationListener() {
            public void operationPerformed(Object object) {
                Scheme copy = (Scheme) object;
                Scheme src = schemeDao.getScheme(me.getId());
                src.setName(copy.getName());
                copy = src;
                schemeDao.addScheme(copy);

                CategoryTreeNode nNode = new CategoryTreeNode(copy);
                ((DefaultTreeModel) getModel()).insertNodeInto(nNode, parentNode, parentNode.getChildCount());
                scheme = null;
                setSelectionPath(new TreePath(nNode.getPath()));
            }
        });
    }

    private void delItem_actionPerformed(ActionEvent e) {
        final CategoryTreeNode node = (CategoryTreeNode) getLastSelectedPathComponent();
        if (node.isRoot()) {
            return;
        }
        Object me = node.getUserObject();

        if(me instanceof Scheme) {
            Scheme s = (Scheme) me;
            s = schemeDao.getScheme(s.getId());
            String message = "要删除方案：" + s.getName();
            String output = s.getOutput();
            File outputFile = null;
            if(output != null && output.trim().length() > 0) {
                outputFile = new File(output.trim());
                if(!outputFile.getPath().equals(outputFile.getAbsolutePath())) {
                    outputFile = new File("jar" + File.separator + outputFile.getPath());
                }
                if(outputFile.exists()) {
                    message += "及其输出："+outputFile.getAbsolutePath();
                }
            }
            int result = JOptionPane.showConfirmDialog(
                    getTopLevelAncestor(), message + "？", null, JOptionPane.OK_CANCEL_OPTION);
            if (result != JOptionPane.OK_OPTION) {
                return;
            }

            if(outputFile != null) {
                outputFile.delete();
            }
            schemeDao.deleteScheme(s.getId());
            scheme = null;
        }
        else if(me instanceof Category) {
            if(node.getChildCount() > 0) {
                JOptionPane.showMessageDialog(getTopLevelAncestor(), "存在子节点，不能删除！");
                return;
            }

            Category c = (Category) me;

            File dir = new File("jar" + File.separator + UIUtils.getCategoryDir(c.getId()));
            if(dir.exists() && dir.isDirectory()) {
                File[] fs = dir.listFiles();
                if(fs != null && fs.length > 0) {
                    JOptionPane.showMessageDialog(getTopLevelAncestor(), dir.getAbsolutePath() + "：目录非空！");
                    return;
                }
            }
            int result = JOptionPane.showConfirmDialog(
                    getTopLevelAncestor(), "要删除分类：" + c.getName() + "？", null, JOptionPane.OK_CANCEL_OPTION);
            if (result != JOptionPane.OK_OPTION) {
                return;
            }
            if(dir.exists()) {
                dir.delete();
            }
            categoryDao.deleteCategory(((Category)me).getId());
        }
        else {
            return;
        }

        DefaultMutableTreeNode nextSelectedNode = node.getNextSibling();
        if (nextSelectedNode == null) {
            nextSelectedNode = (DefaultMutableTreeNode) node.getParent();
        }
        setSelectionPath(new TreePath(nextSelectedNode.getPath()));
        treeModel.removeNodeFromParent(node);
        requestFocus();
    }

    public void checkSave() {
        if(scheme != null) {
            Boolean  isEdited = (Boolean) App.fireCmd(Cmd.IS_EDITED);
            if(isEdited) {
                int result = JOptionPane.showConfirmDialog(
                        getTopLevelAncestor(), "是否要保存当前方案：" + scheme.getName() + "？", "请选择", JOptionPane.YES_NO_OPTION);
                if(result == 0) {
                    App.fireCmd(Cmd.SCHEME_SAVE, false);
                }
            }
        }
    }

    class CategoryTreeCellRenderer extends DefaultTreeCellRenderer {
        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value,
                                                      boolean sel, boolean expanded, boolean leaf, int row,
                                                      boolean hasFocus) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
            Object userObject = node.getUserObject();
            if (userObject instanceof Scheme) {
                Scheme s = (Scheme) userObject;
                //不改变图标
                if(scheme != null && scheme.getId() == s.getId()) {
                    setLeafIcon(ImageUtils.getImageIcon("scheme.png"));
                }
                else {
                    setLeafIcon(ImageUtils.getImageIcon("scheme.png"));
                }
            } else if(userObject instanceof Category){
                if(expanded) {
                    setOpenIcon(ImageUtils.getImageIcon("category.png"));
                }
                else {
                    setClosedIcon(ImageUtils.getImageIcon("category.png"));
                }
            }
            super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
                    row, hasFocus);

            return this;
        }
    }

    class CategoryTreeNode extends DefaultMutableTreeNode {

        //是否已经加载过子节点
        private boolean isLoaded = false;

        public CategoryTreeNode(Object userObject) {
            super(userObject);
        }

        public boolean isLeaf(){
            Object object = getUserObject();
            if(object instanceof Scheme) {
                return true;
            }

            return false;
        }

        /**
         * 加载子节点
         */
        public void load() {
            if(isLoaded) {
                return;
            }
            isLoaded = true;

            Object object = getUserObject();
            if(!(object instanceof Category)) {
                return;
            }

            Category parent = (Category) object;
            //加载分类
            java.util.List<Category> categories = categoryDao.getCategories(parent);
            for (Category category : categories) {
                add(new CategoryTreeNode(category));
            }

            //加载日志
            java.util.List<Scheme> schemes = schemeDao.getSchemes(parent);
            for (Scheme scheme : schemes) {
                add(new CategoryTreeNode(scheme));
            }

            if(treeModel != null) {
                int childrenIdx[]=new int[getChildCount()];
                int i=0;
                for(Enumeration e = children(); e.hasMoreElements();){
                    Object obj=e.nextElement();
                    childrenIdx[i]=getIndex((TreeNode)obj);
                    i++;
                }
                treeModel.nodesWereInserted(this, childrenIdx);
            }
        }
    }

}
